package com.neusoft.neuiotms.dcam.workflow.service.impl;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import javax.persistence.EntityNotFoundException;
import javax.transaction.Transactional;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;

import com.neusoft.bizcore.activiti.dto.ProcessInstanceDTO;
import com.neusoft.bizcore.activiti.model.WorkOrder;
import com.neusoft.bizcore.activiti.repository.WorkOrderRepository;
import com.neusoft.bizcore.activiti.service.ProcessInstanceService;
import com.neusoft.bizcore.activiti.service.WorkOrderService;
import com.neusoft.bizcore.auth.common.bean.UserBean;
import com.neusoft.bizcore.web.constant.ExceptionConstants;
import com.neusoft.bizcore.web.dto.result.ResultListDTO;
import com.neusoft.bizcore.web.exception.UnitedException;
import com.neusoft.bizcore.web.support.Searchable;
import com.neusoft.neuiotms.common.constant.AHConstants;
import com.neusoft.neuiotms.dcam.constant.DCAMConsts;
import com.neusoft.neuiotms.dcam.fixed.converter.AssetConverter;
import com.neusoft.neuiotms.dcam.fixed.dto.AssetDTO;
import com.neusoft.neuiotms.dcam.fixed.dto.AssetLifeCycleDTO;
import com.neusoft.neuiotms.dcam.fixed.dto.WarehouseRecordDTO;
import com.neusoft.neuiotms.dcam.fixed.model.Asset;
import com.neusoft.neuiotms.dcam.fixed.repository.AssetRepository;
import com.neusoft.neuiotms.dcam.fixed.service.AssetLifeCycleService;
import com.neusoft.neuiotms.dcam.fixed.service.AssetService;
import com.neusoft.neuiotms.dcam.fixed.service.StorehouseService;
import com.neusoft.neuiotms.dcam.fixed.service.WarehouseRecordService;
import com.neusoft.neuiotms.dcam.workflow.converter.PeifaSLConverter;
import com.neusoft.neuiotms.dcam.workflow.dto.PeifaItemSLDTO;
import com.neusoft.neuiotms.dcam.workflow.dto.PeifaSLDTO;
import com.neusoft.neuiotms.dcam.workflow.model.PeifaItemSL;
import com.neusoft.neuiotms.dcam.workflow.model.PeifaSL;
import com.neusoft.neuiotms.dcam.workflow.repository.PeifaItemSLRepository;
import com.neusoft.neuiotms.dcam.workflow.repository.PeifaSLRepository;
import com.neusoft.neuiotms.dcam.workflow.service.PeifaSLService;
import com.neusoft.neuiotms.micro.auth.AuthMicroService;

import io.micrometer.core.instrument.util.StringUtils;

@Service
public class PeifaSLServiceImpl implements PeifaSLService {

    @Autowired
    private WorkOrderService workOrderService;
    @Autowired
    private WorkOrderRepository workOrderRepository;
    @Autowired
    private ProcessInstanceService processInstanceService;
    @Autowired
    private PeifaSLRepository peifaSLRepository;
    @Autowired
    private PeifaItemSLRepository peifaItemSLRepository;
    @Autowired
    private PeifaSLConverter peifaSLConverter;
    @Autowired
    private AssetRepository assetRepository;
    @Autowired
    private AssetService assetService;
    @Autowired
    private AssetConverter assetConverter;
    @Autowired
    private AuthMicroService authMicroService;
    @Autowired
    private AssetLifeCycleService assetLifeCycleService;
    @Autowired
    private WarehouseRecordService warehouseRecordService;
    @Autowired
    private StorehouseService storehouseService;

    @Override
    @Transactional
    public PeifaSLDTO create(final PeifaSLDTO dto, final UserBean user) {

        final String taskId = dto.getTaskId();
        final ProcessInstanceDTO instance =
                this.workOrderService.submit(dto.getTitle(), DCAMConsts.PROCESSS_PEIFA_SL_KEY, dto.getWorkOrderNum(),
                        user);
        dto.setTaskId(instance.getTaskId());
        dto.setWorkOrderNum(instance.getWorkorderNum());
        dto.setCreateUser(user.getUsername());
        dto.setCreateUserName(user.getName());

        // 查询当前workOrderNum和TaskId下是否存在记录
        final PeifaSL oldModel = this.peifaSLRepository.findByWorkOrderNumAndTaskId(
                dto.getWorkOrderNum(), taskId);
        if (oldModel == null) {
            dto.setId(null);
        }

        // 解锁以前的资产信息
        final List<PeifaItemSL> all = this.peifaItemSLRepository.findByMain_WorkOrderNum(dto.getWorkOrderNum());
        if (null != all) {
            this.assetService.updateLocked(all.stream().map(l -> l.getCode()).distinct().collect(Collectors.toList()),
                    false);
        }

        PeifaSL model = this.peifaSLConverter.toModel(dto);
        model = this.peifaSLRepository.save(model);

        // 确认节点审批人
        final List<String> users = new ArrayList<>();
        final Map<String, Object> search = new HashMap<>();
        search.put("s_orgCode", dto.getPeifaOrgCode());
        search.put("s_roleCode", AHConstants.ROLE_SL_DEPT_ASSET_ADMIN);
        final ResultListDTO<Map<String, Object>> userList = this.authMicroService.userIndex(search);
        userList.getData().stream().map(l -> l.get("username").toString()).filter(s -> null != s).distinct()
                .forEach(users::add);

        if (users.isEmpty()) {
            throw new UnitedException(dto.getPeifaOrgName() + "部门资产管理员不存在,联系系统管理员");
        }

        this.processInstanceService.setGlobalVariable(dto.getTaskId(), DCAMConsts.PROCESSS_DISPATCHUSERLIST,
                users);

        // 完成当前节点
        this.processInstanceService.complete(dto.getWorkOrderNum(), dto.getTaskId(), user);
        final PeifaSLDTO result = this.peifaSLConverter.toDTO(model);

        // 枷锁资产信息
        this.assetService.updateLocked(
                result.getDetails().stream().map(l -> l.getCode()).distinct().collect(Collectors.toList()),
                true);

        return result;
    }

    @Override
    public PeifaSLDTO detail(final String workOrderNum, final String taskId, final UserBean user) {
        PeifaSL model = null;
        try {
            if (StringUtils.isNotBlank(workOrderNum) && !"NULL".equals(taskId)) {
                model = this.peifaSLRepository.findByWorkOrderNumAndTaskId(workOrderNum, taskId);
                if (model == null) {
                    // 获取前一节点的TaskID
                    final String lastTaskId = this.processInstanceService.getLastTaskId(taskId, user);
                    if (lastTaskId == null) {
                        return new PeifaSLDTO();
                    } else {
                        model = this.peifaSLRepository.findByWorkOrderNumAndTaskId(workOrderNum,
                                lastTaskId);
                    }
                }
            } else if ("NULL".equals(taskId)) {
                model = this.peifaSLRepository.findTopByWorkOrderNumOrderByCreateTimeDesc(workOrderNum);
            }
        } catch (final EntityNotFoundException e) {
            throw new UnitedException(ExceptionConstants.ENTITY_NOT_FOUND,
                    new Object[] {workOrderNum },
                    new Object[] {taskId });
        }
        final PeifaSLDTO modelDto = this.peifaSLConverter.toDTO(model);
        final List<PeifaItemSLDTO> detailItems = modelDto.getDetails();
        for (final PeifaItemSLDTO peifaItemSL : detailItems) {
            final Asset asset = this.assetRepository.findByCode(peifaItemSL.getCode());
            if (asset.getMoney() != null) {
                peifaItemSL.setMoney(asset.getMoney());
            }
            peifaItemSL.setPurpose(asset.getPurpose());
        }
        modelDto.setDetails(detailItems);
        return modelDto;
    }

    @Transactional
    @Override
    public void confirmCreate(final PeifaSLDTO dto, final UserBean user) {
        final PeifaSL model = this.peifaSLRepository.findTopByWorkOrderNumOrderByCreateTimeDesc(dto.getWorkOrderNum());
        if ("1".equals(model.getCategories()) || "2".equals(model.getCategories())) {
            final List<PeifaItemSL> details = model.getDetails().stream().map(l -> {
                final PeifaItemSLDTO one =
                        dto.getDetails().stream().filter(s -> l.getCode().equals(s.getCode())).findFirst().get();
                l.setPeifaLocation(one.getPeifaLocation());
                l.setPeifaLocationName(one.getPeifaLocationName());
                l.setPeifaUserCode(one.getPeifaUserCode());
                l.setPeifaUserName(one.getPeifaUserName());
                final Asset asset = this.assetRepository.findByCode(one.getCode());
                asset.setPurpose(one.getPurpose());
                this.assetRepository.save(asset);
                return l;
            }).collect(Collectors.toList());

            if ((details != null) && (details.size() > 0)) {
                this.peifaItemSLRepository.saveAll(details);
            }
        }

        this.peifaSLCompleteUpdate(dto);
        this.processInstanceService.setGlobalVariable(dto.getTaskId(),
                "passFlag", true);
        this.processInstanceService.complete(dto.getWorkOrderNum(), dto.getTaskId(), user);

    }

    @Override
    public PeifaSLDTO confirmDetails(final String workOrderNum, final String taskId, final UserBean user) {
        final PeifaSL model =
                this.peifaSLRepository.findTopByWorkOrderNumOrderByCreateTimeDesc(workOrderNum);
        final PeifaSLDTO modelDto = this.peifaSLConverter.toDTO(model);
        final List<PeifaItemSLDTO> detailItems = modelDto.getDetails();
        for (final PeifaItemSLDTO peifaItemSL : detailItems) {
            final Asset asset = this.assetRepository.findByCode(peifaItemSL.getCode());
            if (asset.getMoney() != null) {
                peifaItemSL.setMoney(asset.getMoney());
            }
            peifaItemSL.setPurpose(asset.getPurpose());
        }
        modelDto.setDetails(detailItems);
        return modelDto;
    }

    private void peifaSLCompleteUpdate(final PeifaSLDTO dto) {
        final List<AssetLifeCycleDTO> lifeList = new ArrayList<>();
        final List<String> codes = dto.getDetails().stream().map(l -> l.getCode()).collect(Collectors.toList());
        final List<PeifaItemSLDTO> details = dto.getDetails();
        final List<Asset> saveData = new ArrayList<>();
        final List<WarehouseRecordDTO> records = new ArrayList<>();

        if ((codes != null) && (codes.size() > 0)) {
            final List<Asset> assets = this.assetRepository.findByCodeIn(codes);
            if (null != assets) {
                switch (dto.getCategories()) {
                case "3":
                    assets.stream().map(l -> {
                        final List<Asset> list = new ArrayList<>();
                        final PeifaItemSLDTO one =
                                details.stream().filter(s -> s.getCode().equals(l.getCode())).findFirst().get();
                        l.setLocked(false);
                        l.setAmount(l.getAmount() - one.getPeifaQuantity());
                        list.add(l);

                        final Asset model = this.assetRepository.findByCode(l.getCode());
                        // 判断是否为库房
                        if (this.storehouseService.LocationIsStorehouse(model.getLocation())) {
                            records.add(WarehouseRecordDTO.builder()
                                    .name(model.getName())
                                    .specifications(model.getSpecifications())
                                    .brand(model.getBrand())
                                    .smallTypeName(model.getSmallTypeName())
                                    .smallTypeCode(model.getSmallTypeName()).contractNo(model.getContractNo())
                                    .contractName(model.getContractName()).amount(one.getPeifaQuantity())
                                    .location(model.getLocation())
                                    .locationName(model.getLocationName()).type("2").build());
                        }

                        final Asset xh =
                                this.assetRepository
                                        .findTopBySmallTypeCodeAndSpecificationsAndManagementOrgCodeOrderByCreateTimeDesc(
                                                l.getSmallTypeCode(), l.getSpecifications(), dto.getPeifaOrgCode());
                        if (xh != null) {
                            xh.setAmount(xh.getAmount() + one.getPeifaQuantity());
                            list.add(xh);

                            // 生命周期
                            lifeList.add(AssetLifeCycleDTO.builder().code(xh.getCode())
                                    .lifeCycle(DCAMConsts.ASSET_LIFE_TYPE_JILU)
                                    .content("数量为" + one.getPeifaQuantity() + "的" + l.getSmallTypeName() + "已配发")
                                    .workNum(dto.getWorkOrderNum()).build());

                        } else {
                            AssetDTO assetDTO = this.assetConverter.toDTO(l);
                            assetDTO.setId(null);
                            assetDTO.setAmount(one.getPeifaQuantity());
                            assetDTO.setManagementOrgName(dto.getPeifaOrgName());
                            assetDTO.setManagementOrgCode(dto.getPeifaOrgCode());
                            assetDTO.setAmount(0);
                            assetDTO = this.assetService.create(assetDTO, null, null);

                            // 生命周期
                            lifeList.add(AssetLifeCycleDTO.builder().code(assetDTO.getCode())
                                    .lifeCycle(DCAMConsts.ASSET_LIFE_TYPE_JILU)
                                    .content("数量为" + one.getPeifaQuantity() + "的" + l.getSmallTypeName() + "已配发")
                                    .workNum(dto.getWorkOrderNum()).build());
                        }

                        // 生命周期
                        lifeList.add(AssetLifeCycleDTO.builder().code(l.getCode())
                                .lifeCycle(DCAMConsts.ASSET_LIFE_TYPE_JILU)
                                .content("数量为" + one.getPeifaQuantity() + "的" + l.getSmallTypeName() + "配发给"
                                        + dto.getPeifaOrgName() + "部门")
                                .workNum(dto.getWorkOrderNum()).build());

                        return list;

                    }).forEach(saveData::addAll);
                    break;
                default:
                    assets.stream().map(l -> {
                        final PeifaItemSLDTO one =
                                details.stream().filter(s -> s.getCode().equals(l.getCode())).findFirst().get();
                        l.setLocked(false);
                        l.setLocation(one.getPeifaLocation());
                        l.setLocationName(one.getPeifaLocationName());
                        l.setManagementOrgName(dto.getPeifaOrgName());
                        l.setManagementOrgCode(dto.getPeifaOrgCode());
                        l.setManagementUserCode(one.getPeifaUserCode());
                        l.setManagementUserName(one.getPeifaUserName());
                        l.setStatus(DCAMConsts.ASSET_STATUS_USED);

                        // 生命周期
                        lifeList.add(AssetLifeCycleDTO.builder().code(l.getCode())
                                .lifeCycle(DCAMConsts.ASSET_LIFE_TYPE_PEIFA)
                                .content(l.getName() + "已配发").workNum(dto.getWorkOrderNum()).build());
                        return l;
                    }).forEach(saveData::add);

                    break;
                }

            }
        }

        if (lifeList.size() > 0) {
            this.assetLifeCycleService.batchCreate(lifeList);
        }

        if (saveData.size() > 0) {
            this.assetRepository.saveAll(saveData);
        }

        if (records.size() > 0) {
            this.warehouseRecordService.batchCreate(records);
        }
    }

    @Override
    public List<PeifaSLDTO> search(Searchable searchable) {
        final List<PeifaSL> models = this.peifaSLRepository.search(searchable);
        return this.peifaSLConverter.toListDTO(models);
    }

    @Override
    public Page<PeifaSLDTO> search(Pageable pageable, Searchable searchable) {

        final Searchable params = new Searchable();
        params.put("type", "PeifaSL");
        params.put("status", "finish");
        final List<WorkOrder> finishedWorkorderList = this.workOrderRepository.search(params);
        final List<String> finishedWorkorderWorkNumList =
                finishedWorkorderList.stream().map(it -> it.getWorkOrderNum()).collect(Collectors.toList());

        searchable.put("workOrderNumIn", finishedWorkorderWorkNumList);

        final Page<PeifaSL> models = this.peifaSLRepository.search(pageable, searchable);
        final Page<PeifaSLDTO> dtos = this.peifaSLConverter.toPageDTO(models);
        return dtos;
    }

    @Override
    public PeifaSLDTO detail(Long id) {
        final PeifaSL model = this.peifaSLRepository.findById(id).orElse(null);
        if (null != model) {

            final PeifaSLDTO dto = this.peifaSLConverter.toDTO(model);

            final List<String> assetCodeList =
                    model.getDetails().stream().map(it -> it.getCode()).collect(Collectors.toList());
            final Searchable params = new Searchable();
            params.put("codes", assetCodeList);
            final List<AssetDTO> assetList = this.assetService.index(params);
            dto.setAssetStandingBook(assetList);
            return dto;
        }
        return null;
    }

}
